//! \file DbEnum.c
//! \brief TODO: Document
// -----------------------------------------------------------------------------
//! This program is free software; you can redistribute it and/or
//! modify it under the terms of the GNU General Public License
//! as published by the Free Software Foundation; either version 2
//! of the License, or (at your option) any later version.
//!
//! This program is distributed in the hope that it will be useful,
//! but WITHOUT ANY WARRANTY; without even the implied warranty of
//! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//! GNU General Public License for more details.
//!
//! You should have received a copy of the GNU General Public License
//! along with this program; if not, write to the Free Software Foundation,
//! Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// -----------------------------------------------------------------------------
#include "DbEnum.h"
#include <string.h>
#include <stdio.h>

namespace DB {

// =====[ Local Definitions ]===================================================
#define dMAX_QUERY_LENGTH 256

// =====[ Local DataTypes ]=====================================================

typedef eDbEnum (*tDefault)(tDB_INST Instance);

typedef struct
{
  eKeyEnum Key;       //!< TODO: comment.
  tDB_INST Instances; //!< The number of instances that are allowed for the associated Key.
  tDefault Default;   //!< TODO: comment.
} tKeyEntry;

typedef tKeyEntry* tKEY_ENTRY;


// =====[ Local Variables ]=====================================================
static sqlite3* pDb = dNULL;
static const char TableName[] = "Boolean";

// SQL Query Strings.
static const char qCreateTable[] = "CREATE TABLE %s"
                                   "("
                                   "  Key INT NOT NULL,"
                                   "  Instance INT NOT NULL,"
                                   "  Value TINYINT NOT NULL"
                                   ")";
static const char qInsertRow[] = "INSERT INTO %s VALUES('%d','%d','%d')";
static const char qSelectRow[] = "SELECT Value FROM %s WHERE Key='%d' AND Instance='%d'";
static const char qUpdateRow[] = "UPDATE %s SET Value='%d' WHERE Key='%d' AND Instance='%d'";


// =====[ Local Functions ]=====================================================
tERROR _DbEnum_Initialize(sqlite3* pDataBase);
static tERROR _DbEnum_CreateTable(void);
static tERROR _DbEnum_CreateKeys(void);
static tERROR _DbEnum_DefaultValues(void);
static int _DbEnum_CountRows(eKeyEnum Key, tDB_INST Instance);


// =====[ Default Functions ]===================================================
static eDbEnum _Default_False(tDB_INST Instance) { Instance = Instance; return (eDB_ENUM_FALSE); }
static eDbEnum _Default_True(tDB_INST Instance)  { Instance = Instance; return (eDB_ENUM_TRUE); }


// =====[ Local Implementation ]================================================

// =============================================================================
//! \var EntryTable
//! \brief TODO: document
// -----------------------------------------------------------------------------
static const tKeyEntry EntryTable[eNUMBER_OF_ENUM_KEYS] =
{
//  Key                               Instances       Default
  { eKEY_APPLICATION_IS_RUNNING,      1,              &_Default_False         },
};



// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
static eDbEnum Get(eKeyEnum Key, tDB_INST Instance, tERROR* pError)
{
  char Query[dMAX_QUERY_LENGTH];
//  char* pErrMsg = dNULL;
  int Result;
  sqlite3_stmt* pStatement = dNULL;
//  const char *data = dNULL;
//  eDbEnum Value = eFALSE; TOOD: something
  eDbEnum Value;

  // Validate our arguments.
//  if (Key >= eNUMBER_OF_ENUM_KEYS) TODO: fault;

  // Create the SQL query.
  memset(&(Query[0]), 0, sizeof(Query));
  sprintf(&(Query[0]), qSelectRow, TableName, Key, Instance);

  // Prepare the SQL query.
  Result = sqlite3_prepare(pDb, &(Query[0]), -1, &pStatement, dNULL);
  if (Result != SQLITE_OK) { } // exit( -1 ); TODO: handle error

  // Step the SQL query.
  while (sqlite3_step(pStatement) == SQLITE_ROW)
    Value = (eDbEnum)sqlite3_column_int(pStatement, 0);

  // Finalize the SQL query..
  sqlite3_finalize(pStatement);

  // Finally, return the value.
  return (Value);
}


// =============================================================================
// FxName
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
static tERROR Set(eKeyEnum Key, tDB_INST Instance, eDbEnum Value)
{
  //  qUpdateRow

    char Query[dMAX_QUERY_LENGTH];
    char* pErrMsg = dNULL;
    int Result;
  //  sqlite3_stmt* pStatement = dNULL;
  //  const char *data = dNULL;

    // Validate our arguments.
  //  if (Key >= eNUMBER_OF_ENUM_KEYS) TODO: fault;

    // Create the SQL query.
    memset(&(Query[0]), 0, sizeof(Query));
    sprintf(&(Query[0]), qUpdateRow, TableName, Value, Key, Instance);

    // Issue the SQL query to insert the row.
    Result = sqlite3_exec(pDb, &(Query[0]), dNULL, 0, &pErrMsg);

  /*

    // Prepare the SQL query.
    Result = sqlite3_prepare(pDb, &(Query[0]), -1, &pStatement, dNULL);
    if (Result != SQLITE_OK) { } // exit( -1 ); TODO: handle error

    // Step the SQL query.
    while (sqlite3_step(pStatement) == SQLITE_ROW)
      Value = (eDbEnum)sqlite3_column_int(pStatement, 0);

    // Finalize the SQL query..
    sqlite3_finalize(pStatement);
  */


    // Finally, return no error.
    return (dNO_ERROR);
}



//  // =============================================================================
//  // Implement: DB_GetEnum
//  // -----------------------------------------------------------------------------
//  eDbEnum DB_GetEnum(eKeyEnum Key, tDB_INST Instance, tERROR* pError)
//  {
//    char Query[dMAX_QUERY_LENGTH];
//    char* pErrMsg = dNULL;
//    int Result;
//    sqlite3_stmt* pStatement = dNULL;
//    const char *data = dNULL;
//    eDbEnum Value = eFALSE;
//
//    // Validate our arguments.
//  //  if (Key >= eNUMBER_OF_ENUM_KEYS) TODO: fault;
//
//    // Create the SQL query.
//    memset(&(Query[0]), 0, sizeof(Query));
//    sprintf(&(Query[0]), qSelectRow, TableName, Key, Instance);
//
//    // Prepare the SQL query.
//    Result = sqlite3_prepare(pDb, &(Query[0]), -1, &pStatement, dNULL);
//    if (Result != SQLITE_OK) { } // exit( -1 ); TODO: handle error
//
//    // Step the SQL query.
//    while (sqlite3_step(pStatement) == SQLITE_ROW)
//      Value = (eDbEnum)sqlite3_column_int(pStatement, 0);
//
//    // Finalize the SQL query..
//    sqlite3_finalize(pStatement);
//
//    // Finally, return the value.
//    return (Value);
//  }


//  // =============================================================================
//  // Implement: DB_SetEnum
//  // -----------------------------------------------------------------------------
//  tERROR DB_SetEnum(eKeyEnum Key, tDB_INST Instance, eDbEnum Value)
//  {
//  //  qUpdateRow
//
//    char Query[dMAX_QUERY_LENGTH];
//    char* pErrMsg = dNULL;
//    int Result;
//  //  sqlite3_stmt* pStatement = dNULL;
//  //  const char *data = dNULL;
//
//    // Validate our arguments.
//  //  if (Key >= eNUMBER_OF_ENUM_KEYS) TODO: fault;
//
//    // Create the SQL query.
//    memset(&(Query[0]), 0, sizeof(Query));
//    sprintf(&(Query[0]), qUpdateRow, TableName, Value, Key, Instance);
//
//    // Issue the SQL query to insert the row.
//    Result = sqlite3_exec(pDb, &(Query[0]), dNULL, 0, &pErrMsg);
//
//  /*
//
//    // Prepare the SQL query.
//    Result = sqlite3_prepare(pDb, &(Query[0]), -1, &pStatement, dNULL);
//    if (Result != SQLITE_OK) { } // exit( -1 ); TODO: handle error
//
//    // Step the SQL query.
//    while (sqlite3_step(pStatement) == SQLITE_ROW)
//      Value = (eDbEnum)sqlite3_column_int(pStatement, 0);
//
//    // Finalize the SQL query..
//    sqlite3_finalize(pStatement);
//  */
//
//
//    // Finally, return no error.
//    return (dNO_ERROR);
//  }

// =============================================================================
// _DbEnum_Initialize
// -----------------------------------------------------------------------------
//! Initializes the boolean keys in the database for usage.
//!
//! \param [in] pDataBase
//!   A pointer to the SQL database.
//!
//! \retval Error
//!   The error status of the requested operation.
//!   - dNO_ERROR: No errors occurred processing the request.
//!   - Otherwise: An error occurred processing the request, check the return
//!                value for more details.
//!   .
// -----------------------------------------------------------------------------
tERROR _DbEnum_Initialize(sqlite3* pDataBase)
{
  // Validate our arguments.
  if (pDataBase == dNULL) return (dERROR_INVALID_ARGUMENT);

  // Retain our database for usage.
  pDb = pDataBase;

  // Create the boolean table in the database.
  _DbEnum_CreateTable();

  // Create all of the database rows for each of the keys.
  _DbEnum_CreateKeys();

  // TODO: stuff...
  _DbEnum_DefaultValues();

  // Finally, return no error.
  return (dNO_ERROR);
}


// =============================================================================
// _DbEnum_CreateTable
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] pDataBase
//!   A pointer to the SQL database.
//!
//! \retval Error
//!   The error status of the requested operation.
//!   - dNO_ERROR: No errors occurred processing the request.
//!   - Otherwise: An error occurred processing the request, check the return
//!                value for more details.
//!   .
// -----------------------------------------------------------------------------
static tERROR _DbEnum_CreateTable(void)
{
  char Query[dMAX_QUERY_LENGTH];
  char* pErrMsg = dNULL;
  int Result;

  // Create the SQL query.
  memset(&(Query[0]), 0, sizeof(Query));
  sprintf(&(Query[0]), qCreateTable, TableName);

  // Issue the SQL query to create the table.
  Result = sqlite3_exec(pDb, &(Query[0]), dNULL, 0, &pErrMsg);

  // Finally, return no error.
  return (dNO_ERROR);
}


// =============================================================================
// _DbEnum_CreateKeys
// -----------------------------------------------------------------------------
//! Creates a row in the database table for each of our key entries.
//!
//! \param [in] pDataBase
//!   A pointer to the SQL database.
//!
//! \retval Error
//!   The error status of the requested operation.
//!   - dNO_ERROR: No errors occurred processing the request.
//!   - Otherwise: An error occurred processing the request, check the return
//!                value for more details.
//!   .
// -----------------------------------------------------------------------------
static tERROR _DbEnum_CreateKeys(void)
{
  char Query[dMAX_QUERY_LENGTH];
  char* pErrMsg = dNULL;
  int Result;
  tKEY_ENTRY pEntry;
  //eKeyEnum Key; // TODO: stuff...
  unsigned int Key;
  tDB_INST Instance;
  eDbEnum Value;

  // Iterate through all of our keys and create them in the database table.
  for (Key = _START_OF_ENUM_KEYS; Key < eNUMBER_OF_ENUM_KEYS; Key++)
  {
    // Get the key entry.
    pEntry = &EntryTable[Key];

    // Safeguard the table.
    if (pEntry->Key != Key) continue; // TODO: bad fault, log

    // Iterate through each instance.
    for (Instance = 0; Instance < pEntry->Instances; Instance++)
    {
      // Determine the default value.
      Value = pEntry->Default(Instance);

      // Determine if the row already exists in the table.
      if (_DbEnum_CountRows(Key, Instance) != 0) continue;

      // Create the SQL query.
      memset(&(Query[0]), 0, sizeof(Query));
      sprintf(&(Query[0]), qInsertRow, TableName, Key, Instance, (char)Value);

      // Issue the SQL query to insert the row.
      Result = sqlite3_exec(pDb, &(Query[0]), dNULL, 0, &pErrMsg);
    }
  }

  // Finally, return no error.
  return (dNO_ERROR);
}


// =============================================================================
// _DbEnum_DefaultValues
// -----------------------------------------------------------------------------
//! TODO: document
//!
//! \param [in] pDataBase
//!   A pointer to the SQL database.
//!
//! \retval Error
//!   The error status of the requested operation.
//!   - dNO_ERROR: No errors occurred processing the request.
//!   - Otherwise: An error occurred processing the request, check the return
//!                value for more details.
//!   .
// -----------------------------------------------------------------------------
static tERROR _DbEnum_DefaultValues(void)
{


  // Finally, return no error.
  return (dNO_ERROR);
}


// =============================================================================
// _DbEnum_CountRows
// -----------------------------------------------------------------------------
//! Counts the number of rows meeting hte cr
//!
//! \param [in] Arg
//!   TODO: document
//!
//! \retval Exception
//!   The success status of the requested operation.
//!   - eOKAY: Execution occurred as requested.
//!   .
//!
//! \b Example: \code
//! FxName(0);
//! \endcode
// -----------------------------------------------------------------------------
static int _DbEnum_CountRows(eKeyEnum Key, tDB_INST Instance)
{
  char Query[dMAX_QUERY_LENGTH];
  sqlite3_stmt* pStatement = dNULL;
  int Count, Result;

  // Validate our arguments.
  if (Key >= eNUMBER_OF_ENUM_KEYS) return (0);

  // Create the SQL query.
  memset(&(Query[0]), 0, sizeof(Query));
  sprintf(&(Query[0]), qSelectRow, TableName, Key, Instance);

  // Prepare the SQL query.
  Result = sqlite3_prepare(pDb, &(Query[0]), -1, &pStatement, dNULL);
  if (Result != SQLITE_OK) return (0);

  // Step the SQL query.
  Count = 0; // Initialize our count to 0.
  while (sqlite3_step(pStatement) == SQLITE_ROW) Count++;

  // Finalize the SQL query..
  sqlite3_finalize(pStatement);

  // Finally, return the count of rows..
  return (Count);
}

} // namespace DB


